home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / utility / uwserver.zip / uwserver.tar / server / uw_ipc.c < prev    next >
C/C++ Source or Header  |  1991-01-25  |  13KB  |  522 lines

  1. /*
  2.  *    uw IPC
  3.  *
  4.  * Copyright 1986 by John D. Bruner.  All rights reserved.  Permission to
  5.  * copy this program is given provided that the copy is not sold and that
  6.  * this copyright notice is included.
  7.  */
  8.  
  9. #include <sys/types.h>
  10. #include <sys/file.h>
  11. #include <sys/stat.h>
  12. #include <sys/socket.h>
  13. #include <sys/un.h>
  14. #include <sys/ioctl.h>
  15. #include <sys/uio.h>
  16. #include <netinet/in.h>
  17. #include <strings.h>
  18. #include <netdb.h>
  19. #include <errno.h>
  20. #include <stdio.h>
  21.  
  22. #include "uw_param.h"
  23. #include "uw_err.h"
  24. #include "uw_opt.h"
  25. #include "uw_win.h"
  26. #include "uw_fd.h"
  27. #include "uw_pcl.h"
  28. #include "uw_ipc.h"
  29.  
  30. #ifndef ntohs
  31. /* declaring these as one-element arrays or as NULL pointers is a HACK */
  32. extern unsigned long ntohl(), htonl();
  33. extern unsigned short ntohs(), htons();
  34. static struct netadj na_ntoh[1] = {
  35.     (short (*)())ntohs, (long (*)())ntohl, ntohs, ntohl
  36. };
  37. static struct netadj na_hton[1] = {
  38.     (short (*)())htons, (long (*)())htonl, htons, htonl
  39. };
  40. #else
  41. static struct netadj *na_ntoh = NULL;
  42. static struct netadj *na_hton = NULL;
  43. #endif
  44.  
  45. static int have_udport;
  46. static char uipc_port[] = "/tmp/uwXXXXXX";
  47.  
  48. static int inet_sd;
  49. static struct ipcmsg {
  50.     int        im_len;
  51.     struct uwipc    im_msg;
  52. } *inet_buf;
  53.  
  54. extern int errno;
  55.  
  56. ipc_init(use_uipc)
  57. {
  58.     ipc_isinit();
  59.     if (use_uipc)
  60.         ipc_udinit();
  61. }
  62.  
  63.  
  64. /*
  65.  * UNIX-domain
  66.  */
  67.  
  68. static
  69. ipc_udinit()
  70. {
  71.     register int len;
  72.     register char *cp;
  73.     register fildes_t sd;
  74.     auto struct sockaddr_un sa;
  75.     auto char *env[2];
  76.     extern char *mktemp();
  77.  
  78.     len = strlen(UIPC_ENV) + sizeof uipc_port + 1;
  79.     if ((cp = malloc(len)) != NULL) {
  80.         (void)sprintf(cp, "%s=%s", UIPC_ENV, mktemp(uipc_port));
  81.         env[0] = cp;
  82.         env[1] = (char *)0;
  83.         env_set(env);
  84.  
  85.         sa.sun_family = AF_UNIX;
  86.         (void)strncpy(sa.sun_path, uipc_port, sizeof sa.sun_path-1);
  87.         sa.sun_path[sizeof sa.sun_path-1] = '\0';
  88.         if ((sd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0 &&
  89.             bind(sd,&sa,sizeof sa.sun_family+strlen(sa.sun_path)) >= 0){
  90.             have_udport = 1;
  91.             (void)chmod(uipc_port, S_IREAD|S_IWRITE);
  92.             (void)fcntl(sd, F_SETFL, FNDELAY);
  93.             fdmap[sd].f_type = FDT_UDSOCK;
  94.             FD_SET(sd, &selmask[0].sm_rd);
  95.         }
  96.     }
  97. }
  98.  
  99. ipc_exit()
  100. {
  101.     if (have_udport)
  102.         (void)unlink(uipc_port);
  103. }
  104.  
  105. ipc_udrecv(sd)
  106. register fildes_t sd;
  107. {
  108.     register struct window *w;
  109.     register int cnt;
  110.     struct msghdr msg;
  111.     auto int fd;
  112.     struct iovec iov;
  113.     struct stat st1, st2;
  114.     union {
  115.         struct uwipc uwip;
  116.         char data[1024];
  117.     } buf;
  118.  
  119.  
  120.     /*
  121.      * main() calls this routine when there is a message waiting on
  122.      * the UNIX-domain socket.  The message's access rights are
  123.      * expected to contain the file descriptor for the "master" side
  124.      * of a pseudo-tty.  The message contains the name of the pty.
  125.      * The sender is expected to start up a process on the slave side
  126.      * of the pty.  This allows the host end to create windows which
  127.      * run something other than the shell.
  128.      */
  129.     fd = -1;
  130.  
  131.     iov.iov_base = (caddr_t)buf.data;
  132.     iov.iov_len = sizeof buf - 1;
  133.  
  134.     msg.msg_name = (caddr_t)0;
  135.     msg.msg_namelen = 0;
  136.     msg.msg_iov = &iov;
  137.     msg.msg_iovlen = 1;
  138.     msg.msg_accrights = (caddr_t)&fd;
  139.     msg.msg_accrightslen = sizeof fd;
  140.  
  141.     if ((cnt=recvmsg(sd, &msg, 0)) < 0 || cnt != buf.uwip.uwip_len)
  142.         return;
  143.     switch (buf.uwip.uwip_cmd) {
  144.     case UWC_NEWT:
  145.         if (msg.msg_accrightslen > 0 && fd >= 0) {
  146.             /*
  147.              * We can't trust the process which connected to us,
  148.              * so we verify that it really passed us a pseudo-tty's
  149.              * file descriptor by checking the device name and its
  150.              * inode number.  [Of course, if someone else wants to
  151.              * hand us a terminal session running under their
  152.              * uid....]
  153.              */
  154.             if (cnt == sizeof buf)
  155.                 cnt--;
  156.             buf.data[cnt] = '\0';
  157.             if (strncmp(buf.uwip.uwip_newt.uwnt_pty,
  158.                 "/dev/pty", sizeof "/dev/pty"-1) ||
  159.                 fstat(fd, &st1) < 0 ||
  160.                 stat(buf.uwip.uwip_newt.uwnt_pty, &st2) < 0 ||
  161.                 st1.st_dev != st2.st_dev ||
  162.                 st1.st_ino != st2.st_ino) {
  163.                 (void)close(fd);
  164.                 return;
  165.             }
  166.             /*
  167.              * OK, we believe the sender.  We allocate a window and
  168.              * tell the Macintosh to create that window on its end.
  169.              * If we have no free windows, then we close the file
  170.              * descriptor (which will terminate the slave process).
  171.              */
  172.             w = PCL_NEWW(0, WC_INTERNAL,
  173.                   buf.uwip.uwip_newt.uwnt_type,
  174.                   (nwin_t)0, buf.uwip.uwip_newt.uwnt_id,
  175.                   fd, (fildes_t)-1);
  176.             if (w != NULL) {
  177.                 (void)strncpy(w->w_tty,
  178.                     buf.uwip.uwip_newt.uwnt_pty,
  179.                     sizeof w->w_tty-1);
  180.                 w->w_tty[5] = 't'; /* switch to "/dev/ttyp?" */
  181.                 utmp_add(w->w_tty);
  182.             } else
  183.                 (void)close(fd);
  184.         }
  185.         break;
  186.     case UWC_OPTION:
  187.         w = win_search(buf.uwip.uwip_option.uwop_id,
  188.             protocol->p_maxwin);
  189.         if (w != NULL) {
  190.             opt_extopt((caddr_t)w, &w->w_optdefn,
  191.                 (woptcmd_t)buf.uwip.uwip_option.uwop_cmd,
  192.                 (woption_t)buf.uwip.uwip_option.uwop_opt,
  193.                 (char *)&buf.uwip.uwip_option.uwop_val,
  194.                 (struct netadj *)0);
  195.         }
  196.         break;
  197.     }
  198. }
  199.  
  200.  
  201. /*
  202.  * Internet domain
  203.  */
  204.  
  205. static
  206. ipc_isinit()
  207. {
  208.     register fildes_t sd;
  209.     register char *cp;
  210.     struct hostent *h;
  211.     struct sockaddr_in sin;
  212.     auto int sinlen;
  213.     char hostname[32];
  214.     char *env[2];
  215.  
  216.     /*
  217.      * Allocate enough buffers for each file descriptor to have one.
  218.      * This is overkill.
  219.      */
  220.     inet_buf = (struct ipcmsg *)malloc(nfds * sizeof(struct ipcmsg));
  221.     if (inet_buf == NULL)
  222.         return;
  223.  
  224.     /*
  225.      * Determine our host name and get an Internet stream socket.
  226.      * We really should specify the protocol here (rather than 0)
  227.      * but we "know" that it defaults to TCP.
  228.      */
  229.     if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  230.         return;
  231.     sin.sin_family = AF_INET;
  232.     sin.sin_port = 0;
  233.     bzero(sin.sin_zero, sizeof sin.sin_zero);
  234.     if (gethostname(hostname, sizeof hostname) < 0 || hostname[0] == '\0')
  235.         (void)strcpy(hostname, "localhost");
  236.     if ((h = gethostbyname(hostname)) != NULL)
  237.         bcopy(h->h_addr, (char *)&sin.sin_addr, h->h_length);
  238.     else
  239.         sin.sin_addr.s_addr = htonl(0x7f000001L); /* 128.0.0.1 (lo0) */
  240.     if (bind(sd, &sin, sizeof sin) < 0) {
  241.         /*
  242.          * Unable to bind to unspecified port -- try once more with
  243.          * loopback device.  If we already were using the loopback
  244.          * device we just suffer the inefficiency of doing this twice.
  245.          */
  246.         sin.sin_addr.s_addr = htonl(0x7f000001L);
  247.         if (bind(sd, &sin, sizeof sin) < 0) {
  248.             (void)close(sd);
  249.             return;
  250.         }
  251.     }
  252.  
  253.     /*
  254.      * Listen for incoming connections
  255.      */
  256.     if (listen(sd, NWINDOW) < 0) {
  257.         (void)close(sd);
  258.         return;
  259.     }
  260.  
  261.     /*
  262.      * Determine our port number and put our address in the environment.
  263.      */
  264.     sinlen = sizeof sin;
  265.     if (getsockname(sd, (char *)&sin, &sinlen) < 0) {
  266.         /* huh?  Oh well, give up */
  267.         (void)close(sd);
  268.         return;
  269.     }
  270.     if ((cp = malloc(sizeof INET_ENV + 1 + 8 + 1 + 5)) == NULL) {
  271.         /* no memory, give up */
  272.         (void)close(sd);
  273.         return;
  274.     }
  275.     sprintf(cp, "%s=%08lx.%05u", INET_ENV,
  276.         ntohl(sin.sin_addr.s_addr), ntohs(sin.sin_port));
  277.     env[0] = cp;
  278.     env[1] = (char *)0;
  279.     env_set(env);
  280.  
  281.     inet_sd = sd;
  282.     fdmap[sd].f_type = FDT_ISSOCK;
  283.     FD_SET(sd, &selmask[0].sm_rd);
  284. }
  285.  
  286. ipc_isrecv(sd)
  287. register fildes_t sd;
  288. {
  289.     register fildes_t fd;
  290.     register struct uwipc *uwip;
  291.     register struct window *w;
  292.     register uwerr_t uwerr;
  293.     register int len;
  294.     struct sockaddr sin;
  295.     struct uwipc reply;
  296.     auto int sinlen;
  297.  
  298.     /*
  299.      * This routine is called when one of two conditions occur.  It is
  300.      * called when an outside process tries to establish a steam
  301.      * Internet connection.
  302.      *
  303.      * Later, as soon as data is available, this routine will be
  304.      * called again to handle the external message (which must be
  305.      * a "new window" command).
  306.      */
  307.     if (sd == inet_sd) {
  308.         sinlen = sizeof sin;
  309.         if ((fd = accept(sd, &sin, &sinlen)) >= 0) {
  310.             (void)fcntl(fd, F_SETFL, FNDELAY);
  311.             fdmap[fd].f_type = FDT_ISSOCK;
  312.             fdmap[fd].f_win = (struct window *)0;
  313.             FD_SET(fd, &selmask[0].sm_rd);
  314.             inet_buf[fd].im_len = 0;
  315.         }
  316.     } else {
  317.         switch (ipc_getmsg(sd, inet_buf + sd)) {
  318.         case -1:
  319.             (void)close(sd);
  320.             fdmap[sd].f_type = FDT_NONE;
  321.             FD_CLR(sd, &selmask[0].sm_rd);
  322.             FD_CLR(sd, &selmask[0].sm_wt);
  323.             FD_CLR(sd, &selmask[0].sm_ex);
  324.             break;
  325.         case 1:
  326.             uwip = &inet_buf[sd].im_msg;
  327.             uwerr = UWE_NONE;
  328.             if ((uwip->uwip_len < sizeof(struct uwneww) + 
  329.                 ((char *)&uwip->uwip_neww - (char *)uwip)) ||
  330.                 uwip->uwip_cmd != UWC_NEWW) {
  331.                 uwerr = UWE_NXTYPE;
  332.             } else {
  333.                 fd = ipc_ctlopen(sd,
  334.                     (unsigned)uwip->uwip_neww.uwnw_ctlport);
  335.                 w = PCL_NEWW(0, WC_EXTERNAL,
  336.                       ntohs(uwip->uwip_neww.uwnw_type),
  337.                       (nwin_t)0, ntohl(uwip->uwip_neww.uwnw_id),
  338.                       sd, fd);
  339.                 if (w == (struct window *)0)
  340.                     uwerr = UWE_NXTYPE;    /* for now */
  341.                 else
  342.                     uwerr = UWE_NONE;
  343.             }
  344.             len = sizeof(struct uwstatus) +
  345.                 ((char *)&reply.uwip_status - (char *)&reply);
  346.             reply.uwip_len = htons(len);
  347.             reply.uwip_cmd = htons(UWC_STATUS);
  348.             reply.uwip_status.uwst_err = htons(uwerr);
  349.             reply.uwip_status.uwst_errno = htons(errno);
  350.             if (uwerr == UWE_NONE)
  351.                 reply.uwip_status.uwst_id = htonl(w->w_id);
  352.             else
  353.                 reply.uwip_status.uwst_id = 0;
  354.             (void)write(sd, (char *)&reply, len);
  355.             if (uwerr != UWE_NONE) {
  356.                 (void)close(sd);
  357.                 fdmap[sd].f_type = FDT_NONE;
  358.                 FD_CLR(sd, &selmask[0].sm_rd);
  359.                 FD_CLR(sd, &selmask[0].sm_wt);
  360.                 FD_CLR(sd, &selmask[0].sm_ex);
  361.             }
  362.             inet_buf[sd].im_len = 0;
  363.         }
  364.     }
  365. }
  366.  
  367. ipc_ctlopen(sd, port)
  368. fildes_t sd;
  369. unsigned port;
  370. {
  371.     register int fd;
  372.     auto struct sockaddr_in sin;
  373.     auto int sinlen;
  374.  
  375.     /*
  376.      * Create a control socket and connect it to the same host as
  377.      * "sd" on the specified port.
  378.      */
  379.     sinlen = sizeof sin;
  380.     if (port == 0 ||
  381.         getpeername(sd, (struct sockaddr *)&sin, &sinlen) < 0 ||
  382.         (fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  383.         return(-1);
  384.     } else {
  385.         sin.sin_port = port;
  386.         (void)fcntl(fd, F_SETFL, FNDELAY);
  387.         if (connect(fd, &sin, sinlen) < 0 && errno != EINPROGRESS) {
  388.             (void)close(fd);
  389.             return(-1);
  390.         } else
  391.             return(fd);
  392.     }
  393. }
  394.  
  395. void
  396. ipc_optmsg(win, optcmd, optnum, data, datalen)
  397. caddr_t win;
  398. woptcmd_t optcmd;
  399. woption_t optnum;
  400. char *data;
  401. unsigned datalen;
  402. {
  403.     register struct window *w;
  404.     register int len;
  405.     struct uwipc uwip;
  406.  
  407.     /*
  408.      * Propagate a window option message (WILL, WONT, SET) from the Mac
  409.      * to the remote process (external windows only).
  410.      */
  411.     if ((w = (struct window *)win) != NULL && w->w_alloc &&
  412.         w->w_class == WC_EXTERNAL && w->w_ctlfd >= 0 &&
  413.         optnum <= WONUM_MAX && (optcmd == WOC_WILL || optcmd == WOC_WONT ||
  414.          (optcmd == WOC_SET && data != NULL))) {
  415.         len = datalen +
  416.             ((char *)&uwip.uwip_option.uwop_val - (char *)&uwip);
  417.         uwip.uwip_len = htons(len);
  418.         uwip.uwip_cmd = htons(UWC_OPTION);
  419.         uwip.uwip_option.uwop_id = htonl(w->w_id);
  420.         uwip.uwip_option.uwop_opt = htons(optnum);
  421.         uwip.uwip_option.uwop_cmd = htons(optcmd);
  422.         if (optcmd == WOC_SET) {
  423.             bcopy(data, (char *)&uwip.uwip_option.uwop_val,
  424.                 (int)datalen);
  425.             opt_netadj(w->w_optdefn.wod_optlst[optnum].wol_argdefn,
  426.                 (char *)&uwip.uwip_option.uwop_val, na_hton);
  427.         }
  428.         (void)write(w->w_ctlfd, (char *)&uwip, len);
  429.     }
  430. }
  431.  
  432. ipc_ctlrecv(mfd, sd, win)
  433. fildes_t mfd;
  434. register fildes_t sd;
  435. register struct window *win;
  436. {
  437.     register struct window *w;
  438.     register struct uwipc *uwip;
  439.  
  440.     switch (ipc_getmsg(sd, inet_buf + sd)) {
  441.     case -1:
  442.         (void)close(sd);
  443.         fdmap[sd].f_type = FDT_NONE;
  444.         FD_CLR(sd, &selmask[0].sm_rd);
  445.         FD_CLR(sd, &selmask[0].sm_wt);
  446.         FD_CLR(sd, &selmask[0].sm_ex);
  447.         break;
  448.     case 1:
  449.         uwip = &inet_buf[sd].im_msg;
  450.         switch (uwip->uwip_cmd) {
  451.         case UWC_KILLW:
  452.             if ((uwip->uwip_len == sizeof(struct uwkillw) + 
  453.                 ((char *)&uwip->uwip_killw - (char *)uwip))) {
  454.                 w = win_search(ntohl(uwip->uwip_killw.uwkw_id),
  455.                     protocol->p_maxwin);
  456.                 if (w == win)
  457.                     PCL_KILLW(mfd, w);
  458.             }
  459.             break;
  460.         case UWC_OPTION:
  461.             /* hope the message is long enough... sigh */
  462.             if (uwip->uwip_len > 
  463.              ((char *)&uwip->uwip_option.uwop_val - (char *)uwip)) {
  464.                 w = win_search(ntohl(uwip->uwip_option.uwop_id),
  465.                     protocol->p_maxwin);
  466.                 if (w == win) {
  467.                     opt_extopt((caddr_t)w, &w->w_optdefn,
  468.                         (woptcmd_t)ntohs(uwip->uwip_option.uwop_cmd),
  469.                         (woption_t)ntohs(uwip->uwip_option.uwop_opt),
  470.                         (char *)&uwip->uwip_option.uwop_val,
  471.                         na_ntoh);
  472.                 }
  473.             }
  474.             break;
  475.         }
  476.         inet_buf[sd].im_len = 0;
  477.     }
  478. }
  479.  
  480. ipc_getmsg(sd, im)
  481. register fildes_t sd;
  482. register struct ipcmsg *im;
  483. {
  484.     register int len;
  485.     register char *cp;
  486.  
  487.     /*
  488.      * Read some more bytes from socket "sd" into the message buffer
  489.      * contained in "im".  Return 1 if the message is now complete,
  490.      * -1 if an EOF was reached, or 0 otherwise.  Before returning 1,
  491.      * the byte order of the common parameters (command, length) is
  492.      * changed from network to host order.
  493.      *
  494.      * This routine expects the socket to use non-blocking I/O (which
  495.      * is enabled by ipc_isrecv() when the connection is accepted).
  496.      */
  497.     cp = (char *)&im->im_msg + im->im_len;
  498.     if (im->im_len < sizeof(im->im_msg.uwip_len)) {
  499.         len = read(sd, cp, sizeof im->im_msg.uwip_len - im->im_len);
  500.         if (len == 0 || (len < 0 && errno != EWOULDBLOCK))
  501.             return(-1);
  502.         if ((im->im_len += len) < sizeof im->im_msg.uwip_len)
  503.             return(0);
  504.         im->im_msg.uwip_len = ntohs(im->im_msg.uwip_len);
  505.         if (im->im_msg.uwip_len == sizeof im->im_msg.uwip_len)
  506.             return(1);
  507.         cp += len;
  508.     }
  509.     if (im->im_msg.uwip_len > sizeof(struct ipcmsg))
  510.         im->im_msg.uwip_len = sizeof(struct ipcmsg);
  511.     len = read(sd, cp, im->im_msg.uwip_len - im->im_len);
  512.     if (len == 0)
  513.         return(-1);
  514.     if (len < 0)
  515.         return((errno==EWOULDBLOCK) ? 0 : -1);
  516.     if ((im->im_len += len) == im->im_msg.uwip_len) {
  517.         im->im_msg.uwip_cmd = ntohs(im->im_msg.uwip_cmd);
  518.         return(1);
  519.     } else
  520.         return(0);
  521. }
  522.